#ifndef _DOHOME_LOG_H_
#define _DOHOME_LOG_H_

#include <dohome_cfg.h>
#include <dohome_type.h>
#include <dohome_libc.h>
#include <string.h>
// #include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
extern void dohome_udplog_init(void);
extern DOHOME_CHAR_T *dohome_device_get_dev_id(void);
void dohome_udplog_output(DOHOME_UINT8_T level, const char *tag, const char *format, ...);
void dohome_log_hexdump(const char* tag, const char* buf, int len);
#define DOHOME_LOG_LINE_BUF_SIZE          768
#define DOHOME_UDP_LOG_DID                dohome_device_get_dev_id()

#if DOHOME_LOG_UDP_ENABLE
    #define DOHOME_UDP_LOG                    dohome_udplog_output
#else
    #define DOHOME_UDP_LOG(...)               
#endif

//ERROR才有输出
// #define DOHOME_LOG_FILE_ENABLE             //是否打印文件名
#define DOHOME_LOG_LINE_ENABLE             //是否打印行号
#define DOHOME_LOG_FUNCTION_ENABLE         //是否打印函数

#define DOHOME_LOG_TIME_ENABLE             //是否打印时间

#if DOHOME_LOG_COLOR_ENABLE
#define LOG_COLOR_BLACK   "30"
#define LOG_COLOR_RED     "31"
#define LOG_COLOR_GREEN   "32"
#define LOG_COLOR_BROWN   "33"
#define LOG_COLOR_BLUE    "34"
#define LOG_COLOR_PURPLE  "35"
#define LOG_COLOR_CYAN    "36"
#define LOG_COLOR(COLOR)  "\033[0;" COLOR "m"
#define LOG_BOLD(COLOR)   "\033[1;" COLOR "m"
#define LOG_COLOR_RESET   "\033[0m"
#define LOG_COLOR_E       LOG_COLOR(LOG_COLOR_RED)
#define LOG_COLOR_W       LOG_COLOR(LOG_COLOR_BROWN)
#define LOG_COLOR_I       LOG_COLOR(LOG_COLOR_GREEN)
#define LOG_COLOR_D       LOG_COLOR(LOG_COLOR_CYAN)
#define LOG_COLOR_L       LOG_COLOR(LOG_COLOR_PURPLE)
#else
#define LOG_COLOR_E       ""
#define LOG_COLOR_W       ""
#define LOG_COLOR_I       ""
#define LOG_COLOR_D       ""
#define LOG_COLOR_L       ""
#define LOG_COLOR_RESET   ""
#endif

#ifdef DOHOME_LOG_FILE_ENABLE
    #define DOHOME_LOG_FILE            __FILE__
#else
    #define DOHOME_LOG_FILE            ""
#endif
#ifdef DOHOME_LOG_LINE_ENABLE
    #define DOHOME_LOG_LINE            __LINE__
#else
    #define DOHOME_LOG_LINE            0
#endif
#ifdef DOHOME_LOG_FUNCTION_ENABLE
    #define DOHOME_LOG_FUNCTION        __FUNCTION__
#else
    #define DOHOME_LOG_FUNCTION        ""
#endif
extern DOHOME_UINT32_T dohome_time_get_time(void);
#ifdef DOHOME_LOG_TIME_ENABLE
    // extern struct tm g_tblock;
    // #define DOHOME_LOG_CURR_TIME_HOUR  (g_tblock.tm_hour)
    // #define DOHOME_LOG_CURR_TIME_MIN   (g_tblock.tm_min)
    // #define DOHOME_LOG_CURR_TIME_SEC   (g_tblock.tm_sec)
    #define DOHOME_LOG_CURR_TIMESTAMP      dohome_time_get_time()
#else
    // #define DOHOME_LOG_CURR_TIME_HOUR  0
    // #define DOHOME_LOG_CURR_TIME_MIN   0
    // #define DOHOME_LOG_CURR_TIME_SEC   0
    #define DOHOME_LOG_CURR_TIMESTAMP      0
#endif


#define DOHOME_LOG_NEWLINE         "\r\n"      //新行符号 可选 \r \n
//DOHOME_LOG_TAG 和 DOHOME_LOG_LVL 分别用于控制单个文件内的打印标签和输出级别，须放置在 #include <logger.h> 之前
#if !defined(DOHOME_LOG_TAG)
    #define DOHOME_LOG_TAG          "NO_TAG"
#endif
#if !defined(DOHOME_LOG_LVL)
    #define DOHOME_LOG_LVL          DOHOME_LOG_LVL_DEBUG
#endif
#define DOHOME_LOG_RAW(_fmt_, ...)     do{dohome_printf(_fmt_, ##__VA_ARGS__);}while(0)
//****************************************************************

#define DOHOME_LOG_HEX_DUMP(_fmt_, ...) dohome_log_hexdump(DOHOME_LOG_TAG, _fmt_, ##__VA_ARGS__)

/* NOTE: don't use printf_opt in irq handler, for test */
// #define DOHOME_LOG_RAW(fmt, ...) do {    
//         static const char flash_str[]  = fmt;  
//         printf(flash_str, ##__VA_ARGS__);   
//     } while(0)

#if (DOHOME_LOG_LVL_ALL >= DOHOME_LOG_LVL_ASSERT) && (DOHOME_LOG_LVL >= DOHOME_LOG_LVL_ASSERT)
    #define DOHOME_LOG_ASSERT(EXPR)     \
        do{                 \
            if (!(EXPR))    \
            {               \
                DOHOME_LOG_RAW("[A] (%s) has assert failed at %s %s:%ld.", #EXPR,  DOHOME_LOG_FILE, DOHOME_LOG_FUNCTION, DOHOME_LOG_LINE); \
                            \
            }               \
          } while (0);
#else
    #define DOHOME_LOG_ASSERT(EXPR)
#endif

#if (DOHOME_LOG_LVL_ALL >= DOHOME_LOG_LVL_ERROR) && (DOHOME_LOG_LVL >= DOHOME_LOG_LVL_ERROR)
    #if defined(__GNUC)
        #define DOHOME_LOG_E(_fmt_, ...)       \
            DOHOME_LOG_RAW(LOG_COLOR_E##"%ld [E %s %s:%ld] [%12s] "##_fmt_##""##DOHOME_LOG_NEWLINE##""##LOG_COLOR_RESET, DOHOME_LOG_CURR_TIMESTAMP, DOHOME_LOG_FILE, DOHOME_LOG_FUNCTION, DOHOME_LOG_LINE, DOHOME_LOG_TAG, ##__VA_ARGS__);\
            DOHOME_UDP_LOG(DOHOME_LOG_LVL_WARN, DOHOME_LOG_TAG, "[%ld %s %s:%ld] "_fmt_, DOHOME_LOG_CURR_TIMESTAMP, DOHOME_LOG_FILE, DOHOME_LOG_FUNCTION, DOHOME_LOG_LINE, ##__VA_ARGS__)
    #else
        #define DOHOME_LOG_E(_fmt_, ...)       \
            DOHOME_LOG_RAW(LOG_COLOR_E"%ld [E %s %s:%ld] [%12s] "_fmt_""DOHOME_LOG_NEWLINE""LOG_COLOR_RESET, DOHOME_LOG_CURR_TIMESTAMP, DOHOME_LOG_FILE, DOHOME_LOG_FUNCTION, DOHOME_LOG_LINE, DOHOME_LOG_TAG, ##__VA_ARGS__);\
            DOHOME_UDP_LOG(DOHOME_LOG_LVL_WARN, DOHOME_LOG_TAG, "[%ld %s %s:%ld] "_fmt_, DOHOME_LOG_CURR_TIMESTAMP, DOHOME_LOG_FILE, DOHOME_LOG_FUNCTION, DOHOME_LOG_LINE, ##__VA_ARGS__)
    #endif
#else
    #define DOHOME_LOG_E(_fmt_, ...)
#endif

#if (DOHOME_LOG_LVL_ALL >= DOHOME_LOG_LVL_WARN) && (DOHOME_LOG_LVL >= DOHOME_LOG_LVL_WARN)
    #if defined(__GNUC)
        #define DOHOME_LOG_W(_fmt_, ...)       \
            DOHOME_LOG_RAW(LOG_COLOR_W##"%ld [W] [%12s] "##_fmt_##""##DOHOME_LOG_NEWLINE##""##LOG_COLOR_RESET, DOHOME_LOG_CURR_TIMESTAMP, DOHOME_LOG_TAG, ##__VA_ARGS__);\
            DOHOME_UDP_LOG(DOHOME_LOG_LVL_WARN, DOHOME_LOG_TAG, "[%ld] "##_fmt_, DOHOME_LOG_CURR_TIMESTAMP, ##__VA_ARGS__)
    #else
        #define DOHOME_LOG_W(_fmt_, ...)       \
            DOHOME_LOG_RAW(LOG_COLOR_W"%ld [W] [%12s] "_fmt_""DOHOME_LOG_NEWLINE""LOG_COLOR_RESET, DOHOME_LOG_CURR_TIMESTAMP, DOHOME_LOG_TAG, ##__VA_ARGS__);\
            DOHOME_UDP_LOG(DOHOME_LOG_LVL_WARN, DOHOME_LOG_TAG, "[%ld] "_fmt_, DOHOME_LOG_CURR_TIMESTAMP, ##__VA_ARGS__)
    #endif
#else
    #define DOHOME_LOG_W(_fmt_, ...)
#endif

#if (DOHOME_LOG_LVL_ALL >= DOHOME_LOG_LVL_INFO) && (DOHOME_LOG_LVL >= DOHOME_LOG_LVL_INFO)
    #if defined(__GNUC)
        #define DOHOME_LOG_I(_fmt_, ...)       \
            DOHOME_LOG_RAW(LOG_COLOR_I##"%ld [I] [%12s] "##_fmt_##""##DOHOME_LOG_NEWLINE##""##LOG_COLOR_RESET, DOHOME_LOG_CURR_TIMESTAMP, DOHOME_LOG_TAG, ##__VA_ARGS__);\
            DOHOME_UDP_LOG(DOHOME_LOG_LVL_INFO, DOHOME_LOG_TAG, "[%ld] "##_fmt_, DOHOME_LOG_CURR_TIMESTAMP, ##__VA_ARGS__)
    #else
         #define DOHOME_LOG_I(_fmt_, ...)       \
            DOHOME_LOG_RAW(LOG_COLOR_I"%ld [I] [%12s] "_fmt_""DOHOME_LOG_NEWLINE""LOG_COLOR_RESET, DOHOME_LOG_CURR_TIMESTAMP, DOHOME_LOG_TAG, ##__VA_ARGS__);\
            DOHOME_UDP_LOG(DOHOME_LOG_LVL_INFO, DOHOME_LOG_TAG, "[%ld] "_fmt_, DOHOME_LOG_CURR_TIMESTAMP, ##__VA_ARGS__)
    #endif
#else
    #define DOHOME_LOG_I(_fmt_, ...)
#endif

#if (DOHOME_LOG_LVL_ALL >= DOHOME_LOG_LVL_DEBUG) && (DOHOME_LOG_LVL >= DOHOME_LOG_LVL_DEBUG)
    #if defined(__GNUC)
        #define DOHOME_LOG_D(_fmt_, ...)       \
            DOHOME_LOG_RAW(LOG_COLOR_D##"%ld [D] [%12s] "##_fmt_##""##DOHOME_LOG_NEWLINE##""##LOG_COLOR_RESET, DOHOME_LOG_CURR_TIMESTAMP, DOHOME_LOG_TAG, ##__VA_ARGS__); \
            DOHOME_UDP_LOG(DOHOME_LOG_LVL_DEBUG, DOHOME_LOG_TAG, "[%ld] "##_fmt_, DOHOME_LOG_CURR_TIMESTAMP, ##__VA_ARGS__)
    #else
         #define DOHOME_LOG_D(_fmt_, ...)       \
            DOHOME_LOG_RAW(LOG_COLOR_D"%ld [D] [%12s] "_fmt_""DOHOME_LOG_NEWLINE""LOG_COLOR_RESET, DOHOME_LOG_CURR_TIMESTAMP, DOHOME_LOG_TAG, ##__VA_ARGS__); \
            DOHOME_UDP_LOG(DOHOME_LOG_LVL_DEBUG, DOHOME_LOG_TAG, "[%ld] "_fmt_, DOHOME_LOG_CURR_TIMESTAMP, ##__VA_ARGS__)
    #endif
#else
    #define DOHOME_LOG_D(_fmt_, ...)
#endif

#if (DOHOME_LOG_LVL_ALL == DOHOME_LOG_LVL_LESS)
    #if defined(__GNUC)
        #define DOHOME_LOG_L(_fmt_, ...)       \
            DOHOME_LOG_RAW(LOG_COLOR_L##"%ld [L] [%12s] "##_fmt_##""##DOHOME_LOG_NEWLINE##""##LOG_COLOR_RESET, DOHOME_LOG_CURR_TIMESTAMP, DOHOME_LOG_TAG, ##__VA_ARGS__);\
            DOHOME_UDP_LOG(DOHOME_LOG_LVL_INFO, DOHOME_LOG_TAG, "[%ld] "##_fmt_, DOHOME_LOG_CURR_TIMESTAMP, ##__VA_ARGS__)
    #else
         #define DOHOME_LOG_L(_fmt_, ...)       \
            DOHOME_LOG_RAW(LOG_COLOR_L"%ld [L] [%12s] "_fmt_""DOHOME_LOG_NEWLINE""LOG_COLOR_RESET, DOHOME_LOG_CURR_TIMESTAMP, DOHOME_LOG_TAG, ##__VA_ARGS__);\
            DOHOME_UDP_LOG(DOHOME_LOG_LVL_INFO, DOHOME_LOG_TAG, "[%ld] "_fmt_, DOHOME_LOG_CURR_TIMESTAMP, ##__VA_ARGS__)
    #endif
#else
    #define DOHOME_LOG_L(_fmt_, ...)
#endif

#define DOHOME_LOG_ERR_CODE_INFO    0

#if (defined(DOHOME_LOG_ERR_CODE_INFO) && (DOHOME_LOG_ERR_CODE_INFO == 1))
#define DOHOME_LOGE_CODE(err)           DOHOME_LOG_E("%s(%d)", #err, err)
#else
#define DOHOME_LOGE_CODE(err)           DOHOME_LOG_E("(%d)", err)
#endif

#ifdef __cplusplus
}
#endif


#endif /* _LOGGER_H_ */
